package com.bedpotato.thread;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import com.bedpotato.constants.ProxyClawerConstants;
import com.bedpotato.http.BasicHttpMethod;
import com.bedpotato.po.ProxyPO;
import com.bedpotato.service.ProxyClawerService;
import com.bedpotato.util.ProxyUtil;
import com.bedpotato.vo.SpysProxyVO;

@Component
public class SpysSiteClawerThread implements Runnable {
	Logger logger = Logger.getLogger(SpysSiteClawerThread.class);
	@Resource
	ProxyClawerService proxyClawerService;
	public static void main(String[] args) {
		SpysSiteClawerThread spysSiteClawerThread = ProxyClawerConstants.applicationContext.getBean("spysSiteClawerThread",SpysSiteClawerThread.class);
		spysSiteClawerThread.run();
	}
	@Override
	public void run() {
		logger.info("Spys信息抓取启动");
		Set<ProxyPO> proxySet = getSpysData();
		proxyClawerService.saveProxy(proxySet);
		logger.info("Spys信息抓取结束");
	}

	public Set<ProxyPO> getSpysData() {
		BasicHttpMethod httpMethod = new BasicHttpMethod();
		Set<ProxyPO> proxySet = new HashSet<ProxyPO>();
		Set<SpysProxyVO> spysProxySet = new HashSet<SpysProxyVO>();
		try {
			String pageStr = httpMethod
					.get("http://spys.ru/free-proxy-list/CN/");
			String[] contentStrArray = StringUtils.substringsBetween(pageStr,
					"<tr class=spy", "</tr>");
			for (String contentStr : contentStrArray) {
				String ip = StringUtils.substringBetween(contentStr,
						"class=spy14>", "<script");
				String portEncode = StringUtils.substringBetween(contentStr,
						"spy2>:<\\/font>\"+", ")</script>");
				if (ProxyUtil.isLegalIP(ip)) {
					SpysProxyVO spysProxyVO = new SpysProxyVO();
					spysProxyVO.setIp(ip);
					spysProxyVO.setPortEncode(portEncode);
					spysProxySet.add(spysProxyVO);
				}
			}
			proxySet.addAll(decodeSpyToProxy(spysProxySet));
		} catch (Exception e) {
			logger.error("Spys " + e);
		}
		return proxySet;
	}

	/**
	 * 将Spys抓取的加密后的代理解密
	 * 
	 * @author LiALuN
	 * @param spysProxySet
	 * @return
	 */
	private Set<ProxyPO> decodeSpyToProxy(Set<SpysProxyVO> spysProxySet) {
		Set<ProxyPO> proxySet = new HashSet<ProxyPO>();
		Map<String, String> decodeMap = calSpyPortCode(spysProxySet);
		for (SpysProxyVO spysProxyVO : spysProxySet) {
			String port = spysPortDecode(spysProxyVO.getPortEncode(), decodeMap);
			if (port != null && !port.isEmpty()) {
				ProxyPO proxyPO = new ProxyPO();
				proxyPO.setIp(spysProxyVO.getIp());
				proxyPO.setPort(port);
				proxySet.add(proxyPO);
			}
		}
		return proxySet;
	}

	/**
	 * 加密端口解密
	 * 
	 * @author LiALuN
	 * @param encodePort
	 * @param decodeMap
	 * @return
	 */
	private String spysPortDecode(String encodePort,
			Map<String, String> decodeMap) {
		String port = "";
		if (encodePort == null || encodePort.isEmpty()) {
			return null;
		}
		String[] encodePostSplitArray = encodePort.split("\\+");
		for (String encodePostSplitStr : encodePostSplitArray) {
			String decodeNumber = decodeMap.get(encodePostSplitStr);
			if (decodeNumber == null) {
				return null;
			} else {
				port += decodeNumber;
			}
		}
		return port;
	}

	/**
	 * 通过Spys传入的EncodePort列表，猜测加密端口对应表
	 * 
	 * @author LiALuN
	 * @param spysProxySet
	 * @return
	 */
	private Map<String, String> calSpyPortCode(Set<SpysProxyVO> spysProxySet) {
		int allProxyCount = spysProxySet.size();

		// 对EncodePort进行计数
		Map<String, Integer> encodePortCountMap = new HashMap<String, Integer>();
		for (SpysProxyVO spysProxyVO : spysProxySet) {
			if (encodePortCountMap.containsKey(spysProxyVO.getPortEncode())) {
				encodePortCountMap
						.put(spysProxyVO.getPortEncode(), encodePortCountMap
								.get(spysProxyVO.getPortEncode()) + 1);
			} else {
				encodePortCountMap.put(spysProxyVO.getPortEncode(), 1);
			}
		}
		// 排序
		List<Entry<String, Integer>> encodePortCountList = new ArrayList<Entry<String, Integer>>(
				encodePortCountMap.entrySet());
		Collections.sort(encodePortCountList,
				new Comparator<Entry<String, Integer>>() {
					@Override
					public int compare(Entry<String, Integer> o1,
							Entry<String, Integer> o2) {
						return o2.getValue() - o1.getValue();
					}
				});
		// 对大于10%的进行处理
		Map<String, String> decodeMap = new HashMap<String, String>();
		for (Entry<String, Integer> encodePortCount : encodePortCountList) {
			if (encodePortCount.getValue() > allProxyCount / 10) {
				String[] encodePortSplitArray = encodePortCount.getKey().split(
						"\\+");
				if (encodePortSplitArray != null) {
					if (encodePortSplitArray.length == 4) {
						// 8080
						if (encodePortSplitArray[0]
								.equals(encodePortSplitArray[2])
								&& encodePortSplitArray[1]
										.equals(encodePortSplitArray[3])) {
							if (decodeMap.containsKey(encodePortSplitArray[0])) {
								if (decodeMap.get(encodePortSplitArray[0]) != "8") {
									continue;
								}
							} else {
								decodeMap.put(encodePortSplitArray[0], "8");
							}
							if (decodeMap.containsKey(encodePortSplitArray[1])) {
								if (decodeMap.get(encodePortSplitArray[1]) != "0") {
									continue;
								}
							} else {
								decodeMap.put(encodePortSplitArray[1], "0");
							}
						}// 3128
						else if (!encodePortSplitArray[0]
								.equals(encodePortSplitArray[2])
								&& !encodePortSplitArray[1]
										.equals(encodePortSplitArray[3])) {

							if (decodeMap.containsKey(encodePortSplitArray[0])) {
								if (decodeMap.get(encodePortSplitArray[0]) != "3") {
									continue;
								}
							} else {
								decodeMap.put(encodePortSplitArray[0], "3");
							}

							if (decodeMap.containsKey(encodePortSplitArray[1])) {
								if (decodeMap.get(encodePortSplitArray[1]) != "1") {
									continue;
								}
							} else {
								decodeMap.put(encodePortSplitArray[1], "1");
							}

							if (decodeMap.containsKey(encodePortSplitArray[2])) {
								if (decodeMap.get(encodePortSplitArray[2]) != "2") {
									continue;
								}
							} else {
								decodeMap.put(encodePortSplitArray[2], "2");
							}

							if (decodeMap.containsKey(encodePortSplitArray[3])) {
								if (decodeMap.get(encodePortSplitArray[3]) != "8") {
									continue;
								}
							} else {
								decodeMap.put(encodePortSplitArray[3], "8");
							}
						}// 8081
						else if (encodePortSplitArray[0]
								.equals(encodePortSplitArray[2])
								&& !encodePortSplitArray[1]
										.equals(encodePortSplitArray[3])) {
							if (decodeMap.containsKey(encodePortSplitArray[0])) {
								if (decodeMap.get(encodePortSplitArray[0]) != "8") {
									continue;
								}
							} else {
								decodeMap.put(encodePortSplitArray[0], "8");
							}

							if (decodeMap.containsKey(encodePortSplitArray[1])) {
								if (decodeMap.get(encodePortSplitArray[1]) != "0") {
									continue;
								}
							} else {
								decodeMap.put(encodePortSplitArray[1], "0");
							}

							if (decodeMap.containsKey(encodePortSplitArray[3])) {
								if (decodeMap.get(encodePortSplitArray[3]) != "1") {
									continue;
								}
							} else {
								decodeMap.put(encodePortSplitArray[3], "1");
							}
						}// 9080
						else if (encodePortSplitArray[0]
								.equals(encodePortSplitArray[2])
								&& !encodePortSplitArray[1]
										.equals(encodePortSplitArray[3])) {
							if (decodeMap.containsKey(encodePortSplitArray[0])) {
								if (decodeMap.get(encodePortSplitArray[0]) != "9") {
									continue;
								}
							} else {
								decodeMap.put(encodePortSplitArray[0], "9");
							}

							if (decodeMap.containsKey(encodePortSplitArray[1])) {
								if (decodeMap.get(encodePortSplitArray[1]) != "0") {
									continue;
								}
							} else {
								decodeMap.put(encodePortSplitArray[1], "0");
							}

							if (decodeMap.containsKey(encodePortSplitArray[2])) {
								if (decodeMap.get(encodePortSplitArray[2]) != "8") {
									continue;
								}
							} else {
								decodeMap.put(encodePortSplitArray[2], "8");
							}
						}
					}
					if (encodePortSplitArray.length == 3) {

					}
					if (encodePortSplitArray.length == 2) {

					}
				}
			}
		}
		return decodeMap;
	}
}
